package com.template.utils;

import com.template.common.exception.CommonException;
import com.template.common.exception.PermissionException;
import com.wf.captcha.ArithmeticCaptcha;
import com.wf.captcha.GifCaptcha;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.awt.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.UUID;

/**
 * 随机类型验证码 【字符、算数】
 */
@Component
public class CaptchaUtils {

    private static final long CACHE_EXPIRE = 120;
    private static final int DEFAULT_WIDTH = 130;
    private static final int DEFAULT_HEIGHT = 48;
    private static final int DEFAULT_LEN = 4;
    public static final String CAPTCHA = "captcha";

    private static final List<Integer> ARI_FONT = Arrays.asList(0, 1, 3, 4, 5, 6, 8, 9);

    private static final Random random = new Random();


    @Resource
    RedisUtils redisUtils;


    public static Captcha createCaptcha() throws IOException, FontFormatException {
        return createCaptcha(DEFAULT_WIDTH, DEFAULT_HEIGHT);
    }

    public static Captcha createCaptcha(int width, int height) throws IOException, FontFormatException {
        return createCaptcha(width, height, DEFAULT_LEN);
    }

    public static Captcha createCaptcha(int width, int height, int len) throws IOException, FontFormatException {
        // 二位运算还是三位运算
        int ariCount = random.nextInt(2);
        ariCount = ariCount == 0 ? 2 : 3;
        return createCaptcha(width, height, len, ariCount);
    }

    public static Captcha createCaptcha(int width, int height, int len, int arithmeticCount) throws IOException, FontFormatException {
        int creator = random.nextInt(3);
        int charType = random.nextInt(7);
        // 运算验证中的符号在字体2、7时异常
        int font = creator == 2
                ? ARI_FONT.get(random.nextInt(ARI_FONT.size()))
                : random.nextInt(10);


        Captcha captcha = switch (creator) {
            case 0 -> new SpecCaptcha(width, height, len);
            case 1 -> new GifCaptcha(width, height, len);
            default -> new ArithmeticCaptcha(width, height, arithmeticCount);
        };

        captcha.setCharType(charType);
        captcha.setFont(font);

        return captcha;
    }

    /**
     * 缓存验证码结果，不需要传入key
     */
    public String cacheCaptcha(Captcha captcha) {
        return cacheCaptcha(captcha, CACHE_EXPIRE);
    }

    public String cacheCaptcha(Captcha captcha, long expire) {
        String verCode = captcha.text();
        String key = UUID.randomUUID().toString();
        redisUtils.set(getKey(key), verCode, expire);
        return key;
    }


    /**
     * 验证
     */
    public boolean verifyCaptcha(String key, String verCode) {
        String truthCode = (String) redisUtils.get(getKey(key));
        if (truthCode == null) throw new CommonException("验证码已失效");
        return StringUtils.equals(verCode.toLowerCase(), truthCode.toLowerCase());
    }

    private static String getKey(String key) {
        return CAPTCHA + ":" + key;
    }
}